package treinamentoClassificacao.cln.cdp;

import gerenciaDados.cln.cdp.Medicao;
import gerenciaDados.cln.cgt.PI.DB;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.text.Normalizer;
import java.util.ArrayList;
import java.util.Iterator;

import treinamentoClassificacao.ciu.JanAuditarClassificador;
import weka.classifiers.functions.MultilayerPerceptron;
import weka.core.Attribute;
import weka.core.FastVector;
import weka.core.Instance;
import weka.core.Instances;

public class Auditoria {	
	private ArrayList<Medicao> lstMedAuditoria = null;
	private String ultimaDataTreinamento;
	private Instances trainingSet = null;
	private ArrayList<String> datasAquisicoes;
	private ArrayList<String> datasImportacoes;				
	private ArrayList<String> classes = new ArrayList<String>();
	private ArrayList<String> classes_to_s = new ArrayList<String>();
	
	public Auditoria(String ultimaDataTreinamento) 
	{		
		this.ultimaDataTreinamento = ultimaDataTreinamento;
		lstMedAuditoria = Medicao.getMedicoesAuditoria();
		setTrainingSet();
	}
	
	private void setTrainingSet() 
	{
		int i;
		setClasses();
		Iterator<String> it = classes.iterator();
		FastVector atributos = new FastVector();
		for(i=0; i<13; i++) {
			Attribute a = new Attribute("sensor"+i);
			atributos.addElement(a);
		}
		for(i=0; i<16; i++) {
			Attribute a = new Attribute("procImagem"+i);
			atributos.addElement(a);
		}
		for(i=0; i<11; i++) {
			Attribute a = new Attribute("dadosCamera"+i);
			atributos.addElement(a);
		}
		FastVector attClasse = new FastVector();
		while(it.hasNext()) {
			String classe = it.next();
			attClasse.addElement(classe);
		}
		Attribute classe = new Attribute("classe", attClasse);
		atributos.addElement(classe);
		trainingSet = new Instances("projeto-ip", atributos, 1000);
		trainingSet.setClass(classe);		
		preencheTrainingSet();	
	}
	
	private ArrayList<Integer> getAttrSel(String cfg) throws NumberFormatException, IOException	
	{
		File arquivo = new File("cls" + System.getProperty("file.separator")  + cfg);
		FileReader fr = new FileReader( arquivo );
		BufferedReader br = new BufferedReader(fr);
		ArrayList<Integer> clsTipo_attrsel = new ArrayList<Integer>();
		while( br.ready() ){		
			String linha = br.readLine();				
			clsTipo_attrsel.add( Integer.parseInt(linha.split(";")[0]));
		}		
		fr.close();
		br.close();		
		return clsTipo_attrsel;
	}
	
	private Instance InstanciaFiltrada(Instance IT, ArrayList<Integer> indices) 
	{
		Instance f = new Instance(indices.size());		
		int c=0;
		for (Integer indice : indices) {
			f.setValue( c  , IT.value(indice));			
			c++;
		}						
		return f;		
	}
	
	private void preencheTrainingSet() 
	{
		Iterator<Medicao> it = lstMedAuditoria.iterator();		
		int numAtributos = trainingSet.numAttributes();
		datasAquisicoes = new ArrayList<String>();
		datasImportacoes = new ArrayList<String>();
		
		while(it.hasNext()) {
			Medicao m = it.next();
			
			datasAquisicoes.add(m.getDataAquisicao());
			datasImportacoes.add(m.getDataImportacao());
			
			Instance inst = new Instance(numAtributos);
			int i;
			for(i=0; i<13; i++) {
				inst.setValue((Attribute) trainingSet.attribute(i), m.getDadosSensores()[i]);
			}
			for(i=13; i-13<16; i++) {
				inst.setValue((Attribute) trainingSet.attribute(i), m.getProcImagem()[i-13]);
			}
			for(i=29; i-29<11; i++) {
				inst.setValue((Attribute) trainingSet.attribute(i), m.getDadosCamera()[i-29]);
			}
			String tipoLampadaRaw = m.getTipoLampada();
			String potencia = m.getPotenciaLampada();
			String tipoLampadaRefinada = tipoLampadaRaw.trim().replace(" ", "");
			tipoLampadaRefinada= Normalizer.normalize(tipoLampadaRefinada, Normalizer.Form.NFD);  
			tipoLampadaRefinada = tipoLampadaRefinada.replaceAll("[^\\p{ASCII}]", "").toLowerCase();
			
			inst.setValue((Attribute) trainingSet.attribute(i), potencia+tipoLampadaRefinada);
			
			trainingSet.add(inst);
		}
	}
	
	public int auditar() 
	{
		try 
		{
			
			Object[][] dados = new Object[trainingSet.numInstances()][4];			
			setClasses();						
			ArrayList<Integer> clsTipo_attrsel = getAttrSel("cls.config");
			// captura o classificador
			FileInputStream fis = null;			
			fis = new FileInputStream("cls" + System.getProperty("file.separator")  + "cls.dat");
			ObjectInputStream ois = new ObjectInputStream(fis);			
			MultilayerPerceptron classificador = (MultilayerPerceptron) ois.readObject();			
			fis.close();
			ois.close();
			
			Instance it;
			Double classereal;
			Double classepredita;
			boolean acertou;
			int numacertos=0, numerros=0;
			for(int i=0; i< trainingSet.numInstances();i++){
				it = trainingSet.instance(i);
				classereal = it.value(it.numAttributes()-1);				
				it = InstanciaFiltrada(it, clsTipo_attrsel);							
				double [] vetorpeso = classificador.distributionForInstance(it);
				double [][] categorias = new double[vetorpeso.length][2];
				for(Double k=0.0; k<vetorpeso.length;k++)
				{
					categorias[k.intValue()][0] = k;
					categorias[k.intValue()][1] = vetorpeso[k.intValue()];
				}
				categorias = bubbleSort(categorias);				
				classepredita = categorias[categorias.length-1][0];												
				acertou = classereal.equals(classepredita);
				dados[i][0] = formatarData(datasAquisicoes.get(i));
				dados[i][1] = formatarData(datasImportacoes.get(i));
				dados[i][2] = classes_to_s.get(classereal.intValue());
				dados[i][3] = classes_to_s.get(classepredita.intValue());
				
				if(acertou) 
					numacertos++; 
				else 
					numerros++;
			}				
			Double taxaAcerto = (double)numacertos/(double)(numacertos+numerros);						
			new JanAuditarClassificador(dados,taxaAcerto,ultimaDataTreinamento);			
			
		} catch (Exception e) {			
			e.printStackTrace();
		}		
		
		return 0;
	}	
	
	public double[][] bubbleSort(double v[][]) 
	{  
		  
        for (int i = v.length; i >= 1; i--) 
        {  
            for (int j = 1; j < i; j++) 
            {            
                if (v[j - 1][1] > v[j][1]) 
                {  
                    double aux = v[j][1];  
                    v[j][1] = v[j - 1][1];  
                    v[j - 1][1] = aux;  
                    
                    aux = v[j][0];  
                    v[j][0] = v[j - 1][0];  
                    v[j - 1][0] = aux;
                }  
            }  
        }  
        return v;
    } 

	private String formatarData(String s) 
	{
		return s.substring(8, 10) + "/" + s.substring(5, 7) + "/" + s.substring(0, 4) + " " + s.substring(11, 13) + ":" + s.substring(14, 16) + ":" + s.substring(17, 19);
	}
	
	private void setClasses()
    {
            try 
            {
                    ArrayList<String> tipos = new ArrayList<String>();
                    ArrayList<String> potencias = new ArrayList<String>();
                    classes = new ArrayList<String>();
                    classes_to_s = new ArrayList<String>();
                    Connection con = DB.conecta();
                    PreparedStatement ps;
                    ResultSet rs;
                    
                    
                            ps = con.prepareStatement("select descricao from tipolampada order by cd_tipolampada");
                                                                                    
                    rs = ps.executeQuery();                                
                    while(rs.next())
                    {                                                
                            String raw = rs.getString(1);
                            String refined = raw.trim().replace(" ", "");
                            refined= Normalizer.normalize(refined, Normalizer.Form.NFD);  
                            refined = refined.replaceAll("[^\\p{ASCII}]", "").toLowerCase();
                            tipos.add(refined);
                    }
                    
                    ps = con.prepareStatement("select descricao from potencia order by cd_potencia");                                                                
                    rs = ps.executeQuery();                                
                    while(rs.next())
                    {                                                
                            String raw = rs.getString(1);
                            String refined = raw.trim().replace(" ", "");
                            refined= Normalizer.normalize(refined, Normalizer.Form.NFD);  
                            refined = refined.replaceAll("[^\\p{ASCII}]", "").toLowerCase();
                            potencias.add(refined);
                    }
                    
                    for(String potencia: potencias)
                    {
                            for(String tipo: tipos)
                            {
                                    classes.add(potencia+tipo);
                                    classes_to_s.add(potencia + "W, " + tipo);
                            }
                    }
                    
            } catch (SQLException e) {
                    e.printStackTrace();
            }            
    }
}
